<!DOCTYPE html>
<html lang="zh-CN">
<head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>图片与 Base64 编解码工具</title>
    <style>
        :root {
            --primary-color: #4299e1;
            --primary-hover: #3182ce;
            --secondary-color: #718096;
            --success-color: #48bb78;
            --danger-color: #e53e3e;
            --bg-color: #f7fafc;
            --card-bg: #ffffff;
            --text-color: #2d3748;
            --border-color: #e2e8f0;
            --header-bg: #4a5568;
            --header-text: #ffffff;
        }

        body.dark-theme {
            --bg-color: #1a202c;
            --card-bg: #2d3748;
            --text-color: #e2e8f0;
            --border-color: #4a5568;
            --header-bg: #2d3748;
            --header-text: #e2e8f0;
        }

        * {
            box-sizing: border-box;
            margin: 0;
            padding: 0;
        }

        body {
            font-family: 'Segoe UI', Tahoma, Geneva, Verdana, sans-serif;
            background-color: var(--bg-color);
            color: var(--text-color);
            padding: 20px;
            transition: background-color 0.3s, color 0.3s;
        }

        .theme-toggle {
            position: fixed;
            top: 15px;
            right: 15px;
            padding: 8px 15px;
            background-color: var(--card-bg);
            color: var(--text-color);
            border: 1px solid var(--border-color);
            border-radius: 20px;
            cursor: pointer;
            font-size: 0.9rem;
            z-index: 100;
            transition: all 0.3s ease;
        }

        .theme-toggle:hover {
            background-color: var(--border-color);
        }

        header {
            background-color: var(--header-bg);
            color: var(--header-text);
            padding: 20px;
            text-align: center;
            border-radius: 8px;
            margin-bottom: 20px;
            box-shadow: 0 4px 6px rgba(0, 0, 0, 0.1);
        }

        header h1 {
            font-size: 1.8rem;
            margin-bottom: 10px;
        }

        .container {
            max-width: 1000px;
            margin: 0 auto;
        }

        .tools-container {
            display: flex;
            gap: 20px;
            flex-wrap: wrap;
        }

        @media (max-width: 768px) {
            .tools-container {
                flex-direction: column;
            }
        }

        .tool-panel {
            flex: 1;
            min-width: 300px;
            background-color: var(--card-bg);
            border-radius: 8px;
            padding: 20px;
            box-shadow: 0 4px 6px rgba(0, 0, 0, 0.05);
            display: flex;
            flex-direction: column;
        }

        .panel-header {
            font-size: 1.3rem;
            margin-bottom: 15px;
            padding-bottom: 10px;
            border-bottom: 1px solid var(--border-color);
            color: var(--primary-color);
        }

        .drop-area {
            border: 2px dashed var(--border-color);
            border-radius: 8px;
            padding: 30px 20px;
            text-align: center;
            cursor: pointer;
            transition: border-color 0.3s;
            margin-bottom: 15px;
            background-color: rgba(66, 153, 225, 0.05);
        }

        .drop-area:hover, .drop-area.dragover {
            border-color: var(--primary-color);
            background-color: rgba(66, 153, 225, 0.1);
        }

        .drop-area p {
            margin: 10px 0;
        }

        .file-input {
            display: none;
        }

        .btn {
            display: inline-block;
            padding: 10px 20px;
            background-color: var(--primary-color);
            color: white;
            border: none;
            border-radius: 4px;
            cursor: pointer;
            font-weight: 500;
            text-align: center;
            transition: background-color 0.3s;
            text-decoration: none;
            margin: 5px 0;
            font-size: 0.9rem;
        }

        .btn:hover {
            background-color: var(--primary-hover);
        }

        .btn-block {
            display: block;
            width: 100%;
        }

        .btn-secondary {
            background-color: var(--secondary-color);
        }

        .btn-secondary:hover {
            background-color: #5a6777;
        }

        .btn-success {
            background-color: var(--success-color);
        }

        .btn-success:hover {
            background-color: #38a169;
        }

        textarea {
            width: 100%;
            height: 185px;
            padding: 12px;
            border: 1px solid var(--border-color);
            border-radius: 4px;
            font-family: 'Monaco', 'Menlo', 'Ubuntu Mono', monospace;
            font-size: 14px;
            resize: vertical;
            background-color: var(--card-bg);
            color: var(--text-color);
            margin-bottom: 15px;
        }

        textarea:focus {
            outline: none;
            border-color: var(--primary-color);
            box-shadow: 0 0 0 2px rgba(66, 153, 225, 0.2);
        }

        .preview-container {
            margin-top: 15px;
            text-align: center;
        }

        .preview-title {
            margin-bottom: 10px;
            font-weight: 500;
        }

        #image-preview, #base64-preview {
            max-width: 100%;
            max-height: 200px;
            border: 1px solid var(--border-color);
            border-radius: 4px;
            display: none; /* 默认隐藏 */
        }

        .status-message {
            padding: 10px;
            border-radius: 4px;
            margin-top: 10px;
            text-align: center;
            font-weight: 500;
            display: none;
        }

        .status-success {
            background-color: rgba(72, 187, 120, 0.1);
            color: var(--success-color);
            border: 1px solid var(--success-color);
        }

        .status-error {
            background-color: rgba(229, 62, 62, 0.1);
            color: var(--danger-color);
            border: 1px solid var(--danger-color);
        }

        .instructions {
            background-color: rgba(66, 153, 225, 0.1);
            border: 1px solid var(--primary-color);
            border-radius: 4px;
            padding: 15px;
            margin-top: 20px;
            font-size: 0.9rem;
        }

        .instructions h3 {
            margin-top: 0;
            color: var(--primary-color);
        }

        .instructions ul {
            padding-left: 20px;
        }

        .instructions li {
            margin-bottom: 8px;
        }
    </style>
</head>
<body>

<button class="theme-toggle" onclick="toggleTheme()">🌙 深色模式</button>

<header>
    <h1>🖼️ 图片与 Base64 编解码工具</h1>
    <p>在线图片转 Base64 字符串，或 Base64 字符串转回图片</p>
</header>

<div class="container">

    <div class="tools-container">
        <!-- 图片转 Base64 -->
        <div class="tool-panel">
            <div class="panel-header">📤 图片转 Base64</div>
            <div class="drop-area" id="image-drop-area">
                <p>将图片文件拖拽到此处</p>
                <p>或</p>
                <button class="btn">选择图片文件</button>
                <input type="file" id="image-file-input" class="file-input" accept="image/*">
            </div>
            <button id="copy-base64-btn" class="btn btn-block btn-secondary" disabled>📋 复制 Base64</button>
            <div class="preview-container">
                <div class="preview-title">图片预览:</div>
                <img id="image-preview" alt="图片预览">
            </div>
            <div id="image-status" class="status-message"></div>
        </div>

        <!-- Base64 转图片 -->
        <div class="tool-panel">
            <div class="panel-header">📥 Base64 转图片</div>
            <textarea id="base64-input" placeholder="在此粘贴 Base64 字符串..."></textarea>
            <button id="convert-base64-btn" class="btn btn-block">🔄 转换为图片</button>
            <div class="preview-container">
                <div class="preview-title">图片预览:</div>
                <img id="base64-preview" alt="Base64 转换结果">
            </div>
            <div id="base64-status" class="status-message"></div>
        </div>
    </div>

    <div class="instructions">
        <h3>使用说明</h3>
        <ul>
            <li><strong>图片转 Base64:</strong> 拖拽图片文件到虚线框内，或点击按钮选择文件。转换完成后，图片会显示在下方，Base64 字符串会自动填入右侧文本框。点击“复制 Base64”按钮可将结果复制到剪贴板。</li>
            <li><strong>Base64 转图片:</strong> 将 Base64 字符串粘贴到左侧文本框中，然后点击“转换为图片”按钮。转换成功后，图片会显示在下方。</li>
            <li><strong>隐私安全:</strong> 所有操作均在您的浏览器本地完成，图片和 Base64 数据不会被上传到任何服务器。</li>
        </ul>
    </div>

</div>

<script>
    // DOM 元素
    const imageDropArea = document.getElementById('image-drop-area');
    const imageFileInput = document.getElementById('image-file-input');
    const imagePreview = document.getElementById('image-preview');
    const base64Input = document.getElementById('base64-input');
    const base64Preview = document.getElementById('base64-preview');
    const copyBase64Btn = document.getElementById('copy-base64-btn');
    const convertBase64Btn = document.getElementById('convert-base64-btn');
    const imageStatus = document.getElementById('image-status');
    const base64Status = document.getElementById('base64-status');

    // 主题切换
    function toggleTheme() {
        const body = document.body;
        const button = document.querySelector('.theme-toggle');
        body.classList.toggle('dark-theme');

        if (body.classList.contains('dark-theme')) {
            button.innerHTML = '☀️ 浅色模式';
            localStorage.setItem('theme', 'dark');
        } else {
            button.innerHTML = '🌙 深色模式';
            localStorage.setItem('theme', 'light');
        }
    }

    // 页面加载时检查本地存储的主题偏好
    window.onload = function () {
        const savedTheme = localStorage.getItem('theme');
        const button = document.querySelector('.theme-toggle');
        if (savedTheme === 'dark') {
            document.body.classList.add('dark-theme');
            button.innerHTML = '☀️ 浅色模式';
        }
    };

    // 显示状态消息
    function showStatus(element, message, isSuccess) {
        element.textContent = message;
        element.className = 'status-message';
        element.classList.add(isSuccess ? 'status-success' : 'status-error');
        element.style.display = 'block';
        setTimeout(() => {
            element.style.display = 'none';
        }, 3000);
    }

    // 图片转 Base64 相关逻辑
    function handleImageFile(file) {
        if (!file.type.startsWith('image/')) {
            showStatus(imageStatus, '请选择一个有效的图片文件。', false);
            return;
        }

        const reader = new FileReader();
        reader.onload = function (e) {
            const dataURL = e.target.result;
            base64Input.value = dataURL; // 填入 Base64 文本框
            imagePreview.src = dataURL; // 显示图片预览
            imagePreview.style.display = 'inline';
            copyBase64Btn.disabled = false;
            showStatus(imageStatus, '图片转换成功！', true);
        };
        reader.onerror = function () {
            showStatus(imageStatus, '读取图片文件时出错。', false);
        };
        reader.readAsDataURL(file);
    }

    // 事件监听器：点击选择文件
    imageDropArea.addEventListener('click', () => {
        imageFileInput.click();
    });

    imageFileInput.addEventListener('change', (e) => {
        if (e.target.files && e.target.files[0]) {
            handleImageFile(e.target.files[0]);
        }
    });

    // 事件监听器：拖拽上传
    ['dragenter', 'dragover', 'dragleave', 'drop'].forEach(eventName => {
        imageDropArea.addEventListener(eventName, preventDefaults, false);
    });

    function preventDefaults(e) {
        e.preventDefault();
        e.stopPropagation();
    }

    ['dragenter', 'dragover'].forEach(eventName => {
        imageDropArea.addEventListener(eventName, highlight, false);
    });

    ['dragleave', 'drop'].forEach(eventName => {
        imageDropArea.addEventListener(eventName, unhighlight, false);
    });

    function highlight() {
        imageDropArea.classList.add('dragover');
    }

    function unhighlight() {
        imageDropArea.classList.remove('dragover');
    }

    imageDropArea.addEventListener('drop', handleDrop, false);

    function handleDrop(e) {
        const dt = e.dataTransfer;
        const file = dt.files[0];
        if (file) {
            handleImageFile(file);
        }
    }

    // 复制 Base64 到剪贴板
    copyBase64Btn.addEventListener('click', async () => {
        if (!base64Input.value) return;
        try {
            await navigator.clipboard.writeText(base64Input.value);
            const originalText = copyBase64Btn.textContent;
            copyBase64Btn.textContent = '✅ 已复制!';
            setTimeout(() => {
                copyBase64Btn.textContent = originalText;
            }, 2000);
        } catch (err) {
            console.error('复制失败:', err);
            showStatus(imageStatus, '复制到剪贴板失败。', false);
        }
    });

    // Base64 转图片逻辑
    convertBase64Btn.addEventListener('click', () => {
        const base64String = base64Input.value.trim();
        if (!base64String) {
            showStatus(base64Status, '请输入 Base64 字符串。', false);
            return;
        }

        // 简单验证 Base64 字符串是否以 data:image/ 开头
        if (!base64String.startsWith('data:image/')) {
            showStatus(base64Status, '输入的字符串似乎不是有效的图片 Base64 数据。', false);
            return;
        }

        try {
            base64Preview.src = base64String;
            base64Preview.onload = () => {
                base64Preview.style.display = 'inline';
                showStatus(base64Status, 'Base64 转换成功！', true);
            };
            base64Preview.onerror = () => {
                throw new Error('图片加载失败');
            };
        } catch (e) {
            console.error("Base64 转换错误:", e);
            showStatus(base64Status, `转换失败: ${e.message || '无效的 Base64 字符串'}`, false);
            base64Preview.style.display = 'none';
        }
    });

</script>

</body>
</html>
